/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Author: Huawei OS Kernel Lab
 * Create: Thu Aug 15 16:14:23 2023
 */

#ifndef __LIBLINUX_PAL_H__
#define __LIBLINUX_PAL_H__

#ifdef CONFIG_LIBLINUX
#ifndef __ASSEMBLY__

#define ARCH_HAS_DMA_GET_REQUIRED_MASK

/* liblinux exported symbols */
extern void liblinux_kernel_init(void);
extern void liblinux_do_initcalls(void);
extern int  liblinux_setup_fdt(void *dt_virt);
extern int liblinux_bootfdt_enable(void);
extern void liblinux_enter(int pid, ...);
extern int  liblinux_thread_setup(void);
extern void *liblinux_mm_prepare_map(unsigned long long pa, unsigned long size);
extern void liblinux_mm_prepare_unmap(void *va, unsigned long size);
extern int liblinux_suspend(void);
extern void liblinux_resume(void);
extern int liblinux_suspend_late(void);
extern void liblinux_resume_early(void);
extern void liblinux_time_sync(void);

typedef int(*nl_transmit_handler_t)(const void *msg,
				   unsigned int len, int proto, unsigned int dst);
/* obsolete */
typedef int(*nl_genl_reg_handler_t)(const char *name, const void *fam_info, unsigned long info_len,
				    unsigned int *fam_id_inout, unsigned int *mcgroup_offset_out);
/* obsolete */
typedef int(*nl_genl_unreg_handler_t)(unsigned int fam_id);

#define GEN_NETLINK 1
#define RT_NETLINK 2
#define CUST_NETLINK 3
struct liblinux_nl_info {
	int type;
	union {
		struct {
			const char *name;
			const void *fam_info;
			unsigned long info_len;
			unsigned int fam_id; /* out */
			unsigned int mcgroup_offset; /* out */
		} genl;
		struct {
			const char *name;
		} rtnl;
		struct {
			unsigned int unit;
			unsigned int nr_grp;
		} cust_nl;
	};
};
typedef int(*nl_reg_handler_t)(struct liblinux_nl_info *nl_info);
typedef int(*nl_unreg_handler_t)(struct liblinux_nl_info *nl_info);
struct netlink_pal_handler {
	nl_transmit_handler_t unicast_hdr;
	nl_transmit_handler_t multicast_hdr;
	/* obsolete */
	nl_genl_reg_handler_t genl_reg_hdr;
	/* obsolete */
	nl_genl_unreg_handler_t genl_unreg_hdr;
	nl_reg_handler_t nl_reg_hdr;
	nl_unreg_handler_t nl_unreg_hdr;
};
extern int liblinux_pal_netlink_init(struct netlink_pal_handler *hdr);

/* linker script symbols */
extern char __head_start[];

/* devfs related */
extern  int liblinux_pal_register_chrdev_region(unsigned int major,
		unsigned int baseminor, int minorct,
		const char *name, unsigned int *major_out);

extern void liblinux_pal_unregister_chrdev_region(unsigned int major,
		unsigned int baseminor, int minorct);

extern  int liblinux_pal_register_blkdev_region(unsigned int major,
		const char *name, unsigned int *major_out);
extern void liblinux_pal_unregister_blkdev_region(unsigned int major, const char *name);

void *liblinux_pal_alloc_dma_pool(unsigned int *offset, unsigned long long *paddr);
void *liblinux_pal_alloc_dma_pool_ex(unsigned int *offset, unsigned long long *paddr,
				     unsigned int size);
int liblinux_pal_free_dma_pool(unsigned int offset);
/*
 * CAUTION:
 *   The `dma_alloc` PAL return non-coherent (a.k.a cacheable) dma memory.
 *   It will be removed or replaced by a non-coherent version PAL when all
 *   the dependencies have been removed.
 */
extern void *liblinux_pal_dma_alloc(unsigned int size, unsigned long long *paddr);
extern void *liblinux_pal_dma_alloc_coherent(unsigned int size,
					     unsigned long long *paddr);
extern int liblinux_pal_dma_free(const void *vaddr, unsigned int size);
int liblinux_pal_native_net_rx(unsigned int pool_offset, int shm_len,
			   int rx_len, int offset, int ifindex);
/*
 * Note: After shared ring buffer ready,
 * we should to replace this function to the notification mechanism based on
 * shared ring buffer in future.
 */
struct netdev_rx_cb {
	unsigned int cell_pool_offset;
	int rx_len;
	int offset;
	int linux_devno;
};
#define MAX_RX_CB_NUM 16
int liblinux_pal_native_net_rx_ex(int num, void *data, int data_size);
int liblinux_pal_netdev_alloc_ifindex(int ifindex);

/* IRQ related */
int liblinux_pal_local_irq_save(void);
void liblinux_pal_local_irq_enable(void);
void liblinux_pal_local_irq_disable(void);
void liblinux_pal_local_irq_restore(int disabled);
int liblinux_pal_local_save_flags(void);

/* vmalloc */
extern void *liblinux_pal_vmalloc_range(unsigned long size, unsigned long align,
					unsigned long start, unsigned long end,
					unsigned long prot, const void *caller);
extern void liblinux_pal_vfree(const void *addr);

/* alloc/free for task struct to avoid recursive in thread_setup */
extern void *liblinux_pal_malloc(unsigned long size);
extern void liblinux_pal_free(void *addr);

/* page alloc */
struct liblinux_page_allocator {
	void (*destroy)(const struct liblinux_page_allocator *_allocator);
	int (*extend)(const struct liblinux_page_allocator *_allocator,
		      unsigned int order, unsigned long *rvaddr, int recaim);
	void *(*alloc)(const struct liblinux_page_allocator *_allocator,
		       unsigned int order, unsigned long long *phys);
	void (*free)(const struct liblinux_page_allocator *_allocator,
		     unsigned long vaddr, unsigned int order);
	int (*shrink)(const struct liblinux_page_allocator *_allocator,
		     unsigned long vaddr, unsigned long long paddr, unsigned long size);
	int (*extend_ex)(const struct liblinux_page_allocator *_allocator,
			 unsigned int order, unsigned long *rvaddr, int recaim);
	int (*extend_exact)(const struct liblinux_page_allocator *_allocator,
			    unsigned long size, unsigned long *rvaddr, int recaim);
	void *(*alloc_exact)(const struct liblinux_page_allocator *_allocator,
			     unsigned long size, unsigned long long *phys);
	void (*free_exact)(const struct liblinux_page_allocator *_allocator,
			   unsigned long vaddr, unsigned long size);
	int (*extend_alloc)(const struct liblinux_page_allocator *_allocator,
			    unsigned int extend_order, unsigned int alloc_order,
			    unsigned long *rvaddr, int flags);
	int (*extend_alloc_exact)(const struct liblinux_page_allocator *_allocator,
				  unsigned long extend_size, unsigned long alloc_size,
				  unsigned long *rvaddr, int flags);
	int (*should_reclaim)(void);
};

struct liblinux_pool_base {
	unsigned long kmap_virt_start;
	unsigned long kmap_virt_end;
	unsigned long long phys_offset;
	unsigned int page_sizeorder;
};

struct liblinux_ram_info {
	unsigned long long memstart;
	unsigned long long memend;
	unsigned long long total_ram;
};

#define LIBLINUX_VMEMMAP_POPULATE_ALL	0x01U
#define LIBLINUX_VMEMAP_HIGHMEM		0x02U
struct liblinux_vmmemmap_info {
	/* highmem info */
	unsigned long long page_addr;
	unsigned long long page_size;
	unsigned long long vmemmap_start;
	unsigned long long vmemmap_size;
	unsigned int flags;
};

int liblinux_pal_vmemmap_init(struct liblinux_vmmemmap_info *info);

/*
 * Liblinux pal page alloc initialization.
 *
 * @param pool_base		[I] base info of ldk kmap
 *
 * @param ram_info		[O] ram info if operation succeeds
 *
 * @return OK if operation succeeds.
 */
extern int liblinux_pal_page_alloc_init(struct liblinux_pool_base *pool_base,
					struct liblinux_ram_info *ram_info);

/*
 * Liblinux pal page allocator get.
 *
 * @param allocator_name	[I] name of allocator
 *
 * @return page allocator if operation succeeds.
 */
struct liblinux_page_allocator *liblinux_pal_page_allocator_get(char *allocator_name);

extern int liblinux_pal_reserve_range_name(void *start, unsigned long size,
					   int prot, const char *name);
extern int liblinux_pal_page_alloc_populate(const void *start, unsigned long size);
extern int liblinux_pal_page_alloc_unpopulate(const void *start, unsigned long size);
/* GFP related */
#define LIBLINUX_PAL_GFP_NOFAIL		0x8000U
#define LIBLINUX_PAL_GFP_NORETRY	0x10000U
#define LIBLINUX_PAL_GFP_NOEXTRA	0x8000000U
#define LIBLINUX_PAL_GFP_NOIO		0x2000000U

/* cache related */
#define LIBLINUX_PAL_CACHE_FLUSH_RANGE     0U
#define LIBLINUX_PAL_DCACHE_FLUSH_RANGE    1U
#define LIBLINUX_PAL_ICACHE_FLUSH_RANGE    2U
#define LIBLINUX_PAL_DCACHE_CLEAN_RANGE    3U
#define LIBLINUX_PAL_DCACHE_INVAL_RANGE    4U
#define LIBLINUX_PAL_CACHE_FLUSH_ALL		5U
#define LIBLINUX_PAL_DCACHE_FLUSH_ALL		6U
#define LIBLINUX_PAL_ICACHE_FLUSH_ALL		7U
#define LIBLINUX_PAL_DCACHE_CLEAN_ALL		8U
extern void liblinux_pal_flush_cache_range(unsigned int cmd,
					   unsigned long start, unsigned long end);

/* mm related */
extern void *liblinux_pal_ioremap(unsigned long phys_addr,
				  unsigned long size, unsigned long prot, const void *caller);
extern void *liblinux_pal_ioremap_ex(unsigned long phys_addr, unsigned long size,
				     unsigned long prot, unsigned int flags, const void *caller);
extern int liblinux_pal_remap_pfn_range(unsigned long addr, unsigned long pfn,
				unsigned long size, unsigned long prot, unsigned int flags);
#define LIBLINUX_PAL_REMAP_NONE			0
#define LIBLINUX_PAL_REMAP_CACHE		0x1
#define LIBLINUX_PAL_REMAP_NORMAL_NC		0x2
#define LIBLINUX_PAL_REMAP_DEVICE		0x4

#define LIBLINUX_PAL_VM_TO_USER			(1U << 31)

extern void *liblinux_pal_vm_prepare(unsigned long vaddr, unsigned long size,
				     unsigned long prot, unsigned int flags);
extern int liblinux_pal_vm_mmap(unsigned long paddr, unsigned long vaddr,
				unsigned long size, unsigned long prot,
				unsigned int flags);
extern int liblinux_pal_vm_unmap(const void *addr);
extern int liblinux_pal_vm_zap(unsigned long addr, unsigned long len, unsigned int flags);

extern unsigned long liblinux_pal_usermap_prepare(unsigned long addr, unsigned long len,
						  unsigned long prot, unsigned long flags,
						  void **priv);
extern void liblinux_pal_usermap_finish(const void *priv, int success);
extern int liblinux_pal_usermap_munmap(unsigned long addr, unsigned long len);

extern int liblinux_pal_copy_from_user(void *dst, const void *src, unsigned long n);
extern int liblinux_pal_copy_to_user(void *dst, const void *src, unsigned long n);
extern int liblinux_pal_copy_in_user(void *dst, const void *src, unsigned long n);

extern int liblinux_pal_set_pageattr(const void *addr, int numpages,
				     int set_prot, int clear_prot);

/* kernel module support */
int liblinux_pal_module_alloc_init(const void *base, unsigned long size);
int liblinux_pal_module_alloc_prepare(const void *addr, unsigned long size);
int liblinux_pal_module_alloc_release(const void *addr, unsigned long *psize_out);

extern int liblinux_pal_request_module(const char *modname);

struct liblinux_syminfo {
	void *__start___ksymtab;
	void *__stop___ksymtab;
	void *__start___ksymtab_gpl;
	void *__stop___ksymtab_gpl;
	void *__start___ksymtab_gpl_future;
	void *__stop___ksymtab_gpl_future;
	void *__start___kcrctab;
	void *__start___kcrctab_gpl;
	void *__start___kcrctab_gpl_future;
};
extern int liblinux_init_symbol_module(const char *modname,
		const struct liblinux_syminfo *si);

struct liblinux_mod_syminfo {
	const void *symtab;
	unsigned int symtab_len;
	const char *strtab;
	unsigned int strtab_len;
	const void *module_core;
	unsigned int core_size;
};
extern int liblinux_pal_fill_mod_symbol(const char *name, const struct liblinux_mod_syminfo *si);
extern int liblinux_pal_drop_ko_symbol(const void *module_core);

/* thread related */
typedef struct {
	unsigned long long handle;
	int tid;
} liblinux_pal_thread_handle_t;

int liblinux_pal_thread_create(void *(*fun)(void *), void *arg,
			       liblinux_pal_thread_handle_t *handle);
int liblinux_pal_thread_create_ex(void *(*fun)(void *), void *arg,
				  liblinux_pal_thread_handle_t *handle);
void liblinux_pal_thread_exit(void);
void liblinux_pal_thread_exit_ex(void *exitcode);
int liblinux_pal_thread_join_ex(const liblinux_pal_thread_handle_t *handle,
				void **exitcode);
int liblinux_pal_thread_set_my_data(const void *data);
void *liblinux_pal_thread_get_my_data(void);
void liblinux_pal_thread_init(void);
int liblinux_pal_thread_init_ex(void (*dtor)(void *));
void liblinux_pal_thread_specific_init(unsigned int *offset, unsigned int *key);
void liblinux_pal_thread_yield(void);
int liblinux_pal_thread_setname(const liblinux_pal_thread_handle_t *handle,
				const char *thread_name);
extern int liblinux_pal_thread_getname(char *thread_name);
int liblinux_pal_thread_setaffinity(const liblinux_pal_thread_handle_t *handle,
				    unsigned long mask);
int liblinux_pal_thread_getaffinity(const liblinux_pal_thread_handle_t *handle,
				    unsigned long *mask);
int liblinux_pal_thread_setscheduler(const liblinux_pal_thread_handle_t *handle,
				     int prio, int policy);
int liblinux_pal_is_thread_ctx(void);
void liblinux_pal_thread_dump(void);
int liblinux_pal_thread_inactive(const liblinux_pal_thread_handle_t *handle);

unsigned int liblinux_pal_processor_id(void);
int liblinux_pal_cpu_config(unsigned long *online_mask,
			     unsigned long *cpu_map,
			     unsigned long cpu_nr,
			     int preempt_flag);
extern int liblinux_pal_cpu_config_ex(unsigned long *online_mask, unsigned long size,
				      int preempt_flag);

/* lock related */
#define LIBLINUX_PAL_FUTEX_UNINTERRUPTIBLE	1
#define LIBLINUX_PAL_FUTEX_SHARED		0x100
#define LIBLINUX_PAL_FUTEX_MAX_TIMEOUT		~0ULL

int liblinux_pal_futex_timedwait(volatile int *futex, int val,
				 unsigned long long timeout, /* ns */
				 unsigned long flags);
int liblinux_pal_futex_wake(volatile int *futex);
int liblinux_pal_futex_wake_ex(volatile int *futex, int flags);

/* This data structure and initializer should be aligned to
 * libhmsync/raw_mutex.h
 */
struct liblinux_pal_mutex_t {
	struct {
		union {
			unsigned long id;
			unsigned long long align_id; /* ensure align in 32 and 64 data model */
		};
		union {
			const void *pc;
			unsigned long long align_pc; /* ensure align in 32 and 64 data model */
		};
	} owner;
	unsigned int lock;
	unsigned int waiters;
	unsigned long __rsvd[4];        /* padding for pthread / lock_id */
};

#define LIBLINUX_MUTEX_INITIALIZER {.owner = {{.align_id = 0ULL}, {.align_pc = 0ULL}}, \
					.lock = 0U, .waiters = 0U}

void liblinux_pal_mutex_init(struct liblinux_pal_mutex_t *mutex);
void liblinux_pal_mutex_destroy(struct liblinux_pal_mutex_t *mutex);
void liblinux_pal_mutex_lock(struct liblinux_pal_mutex_t *mutex);
int  liblinux_pal_mutex_trylock(struct liblinux_pal_mutex_t *mutex);
void liblinux_pal_mutex_unlock(struct liblinux_pal_mutex_t *mutex);
int liblinux_pal_mutex_is_locked(struct liblinux_pal_mutex_t *mutex);

/* This data structure should be aligned to
 * libhmsync/raw_thread_cond.h
 */
struct liblinux_pal_cond_t {
	int seq;
	int waiters;
	int lock;

	void *head;
	void *tail;

	unsigned int attr;
	unsigned long __rsvd[4];        /* padding for pthread */
};

struct liblinux_pal_cond_attr_t {
	unsigned int attr;
};

int liblinux_pal_cond_init(struct liblinux_pal_cond_t *cond,
			   const struct liblinux_pal_cond_attr_t *attr);
int liblinux_pal_cond_destroy(struct liblinux_pal_cond_t *cond);
int liblinux_pal_cond_wait(struct liblinux_pal_cond_t *cond, struct liblinux_pal_mutex_t *mutex);
int liblinux_pal_cond_signal(struct liblinux_pal_cond_t *cond);
int liblinux_pal_cond_broadcast(struct liblinux_pal_cond_t *cond);

/* This data structure should be aligned to
 * libhmsync/raw_sem.h
 */
struct liblinux_pal_sem_t {
	volatile int value;
	volatile unsigned int waiters;
	unsigned long __rsvd[4];        /* padding for pthread */
};
struct liblinux_pal_timespec_t {
	long ts_sec;
	long ts_nsec;
};

#define LIBLINUX_SEM_INITIALIZER(n) {.value = n, .waiters = 0}

int liblinux_pal_sem_init(struct liblinux_pal_sem_t *sem, unsigned int value);
int liblinux_pal_sem_trywait(struct liblinux_pal_sem_t *sem);
int liblinux_pal_sem_wait(struct liblinux_pal_sem_t *sem);
int liblinux_pal_sem_timedwait(struct liblinux_pal_sem_t *sem,
			       const struct liblinux_pal_timespec_t *ts);
int liblinux_pal_sem_post(struct liblinux_pal_sem_t *sem);
int liblinux_pal_sem_getvalue(struct liblinux_pal_sem_t *sem);

enum linux_log_level {
	LIBLINUX_LOGLEVEL_EMERG,
	LIBLINUX_LOGLEVEL_ALERT,
	LIBLINUX_LOGLEVEL_CRIT,
	LIBLINUX_LOGLEVEL_ERR,
	LIBLINUX_LOGLEVEL_WARNING,
	LIBLINUX_LOGLEVEL_NOTICE,
	LIBLINUX_LOGLEVEL_INFO,
	LIBLINUX_LOGLEVEL_DEBUG,
	LIBLINUX_LOGLEVEL_CONT = -3, /* KERN_CONT */
};
void liblinux_pal_log_store(int level, const char *txt, int txt_len);

/* procfs related */
#define LIBLINUX_FS_TAG_MASK           0x00FFFFFFU
#define LIBLINUX_FS_REMOTE_TAG_MASK    0x80000000U
#define LIBLINUX_FS_TAG_MIN            1
#define LIBLINUX_FS_TAG_MAX            ((int)(LIBLINUX_FS_TAG_MASK))
struct liblinux_pal_kernfs_ops {
	int (*read)(unsigned long long pos, unsigned long ubuf, unsigned long size,
		    void *ctx, unsigned long *rsize /* out */);
	int (*write)(unsigned long long pos, unsigned long ubuf, unsigned long size,
		     void *ctx, unsigned long *wsize /* out */);
	int (*poll)(int (*callback)(void *ctx, int pollable), int id, int pollable);
};

int liblinux_pal_procfs_create_file(const char *name,
				    struct liblinux_pal_kernfs_ops *ops,
				    void *ctx, unsigned int mode);
int liblinux_pal_procfs_create_dir(const char *name, unsigned int mode);
int liblinux_pal_procfs_create_link(const char *name, unsigned int mode,
				    char *linkdata);
int liblinux_pal_procfs_delete(const char *name);
/* request firmware related */
int liblinux_pal_fw_acquire_contents(const char *filename, void *data,
				     unsigned int size, unsigned int *rsize /* out */);

/* wakeup source related */
int liblinux_pal_ws_activate(void);
int liblinux_pal_ws_deactivate(void);

/* fs related */
enum liblinux_fs_type {
	LIBLINUX_SYSFS = 1,
	MAX_FS_TYPE, /* always be the last one */
};

void *liblinux_pal_fget(int fd);
int liblinux_pal_get_unused_fd_flags(unsigned int flags);
void liblinux_pal_fd_install(unsigned int fd, void *file);
void liblinux_pal_put_unused_fd(unsigned int fd);
void *liblinux_pal_transfs_fget(int fd);
void liblinux_pal_transfs_fput(void *file);
int liblinux_pal_require_frange(int type, int *min, int *max);

/*
 * used to adapt fget for anon fd, should be removed when all files use
 * hm fd in LDK
 */
enum liblinux_fd_type {
	DEFAULT_FD = 0,
	ANON_FD,
	TRANSFS_FD,
	MAX_FD, /* always be the last one */
};
void *liblinux_pal_fget_ex(enum liblinux_fd_type fd_type, int fd, void (*fget)(void *));
void liblinux_pal_fput_ex(enum liblinux_fd_type fd_type, void *file);

/* sysfs related */
int liblinux_pal_sysfs_register_ops(void *ops);

int liblinux_pal_sysfs_create_dir(const char *name, unsigned int mode);

int liblinux_pal_sysfs_create_file(const char *name, unsigned int mode,
				   struct liblinux_pal_kernfs_ops *fops,
				   void *ctx);

int liblinux_pal_sysfs_create_link(const char *name, unsigned int mode,
				   const char *linkdata);

int liblinux_pal_sysfs_delete(const char *name);
int liblinux_pal_sysfs_notify(const void *ctx, const char *name);

struct of_device_id;
int liblinux_register_irqchip_table(const struct of_device_id *table);

/* cpuhp related */
int liblinux_cpu_up(unsigned int cpu);
int liblinux_cpu_down(unsigned int cpu);

/* reboot related */
#define LIBLINUX_REBOOT_FLAG_TAKE_SNAPSHOT	(1U) /* bit[0] */
#define LIBLINUX_REBOOT_FLAG_EMERGENCY		(1U << 1) /* bit[1] */

void liblinux_reboot(unsigned int flag, const char *reason);
void liblinux_shutdown(void);

#define THREAD_SCHED_LEVEL_MAX 2
#define PROCESS_SCHED_LEVEL_MAX 2
/* preempt related */
void liblinux_pal_preempt_enable(void);
void liblinux_pal_preempt_disable(void);
void liblinux_pal_process_set_slv(unsigned int cpu, unsigned int slv);
void liblinux_pal_thread_set_slv(const liblinux_pal_thread_handle_t *handle, unsigned int slv);

struct tty_info {
	int tty_sid;
	unsigned int tty_dev_no;
	char *tty_name;
	unsigned int f_mode;
};
int liblinux_pal_set_control_terminal(struct tty_info *info, int preempt);
int liblinux_pal_get_sid(void);
int liblinux_pal_get_pgid(void);
int liblinux_pal_set_pgrp(int tty_sid, int pgrp);
int liblinux_pal_get_pgrp(int tty_sid);
void liblinux_pal_process_signal(int sid, int sig);
void liblinux_pal_process_signal_with_pid(int pid, int sig);
int liblinux_pal_signal_isignored(int pid, int sig);
int liblinux_pal_current_pgrp_isorphaned(void);
void liblinux_pal_sys_shutdown(void);
void liblinux_pal_sys_snapshot(void);

/* rcu related */
extern void liblinux_pal_rcu_init(unsigned long rsv_size);
extern void liblinux_pal_rcu_read_lock(void);
extern void liblinux_pal_rcu_read_unlock(void);
extern void liblinux_pal_synchronize_rcu(void);
extern void liblinux_pal_call_rcu(void *ebr_entry, void *cb);

void liblinux_synchronize_rcu(void);

#ifdef CONFIG_KASAN
extern void liblinux_pal_kasan_poison(const void *address, unsigned long size, unsigned char value);
extern void liblinux_pal_kasan_check(unsigned long addr, unsigned long size,
				unsigned int is_write, unsigned long ret_addr);
extern void liblinux_pal_kasan_report(unsigned long addr, unsigned long size,
				unsigned int is_write, unsigned long ret_addr);
#endif

typedef void (*liblinux_mem_hook_t)(int ev, void *addr, unsigned long size,
				    const void *data);

int liblinux_dfx_vmalloc_hook(liblinux_mem_hook_t hook);
int liblinux_dfx_mem_hook(liblinux_mem_hook_t hook);
int liblinux_pal_mincore(const void *addr, unsigned long size, unsigned char *vec);

/* capabilities */
int liblinux_pal_in_group_p(unsigned int gid);
int liblinux_pal_in_egroup_p(unsigned int gid);
int liblinux_pal_capable(int cap);

/* kernel livepatch */
typedef int (*klp_stacktrace_t)(unsigned long, unsigned long, unsigned long, void *);
int liblinux_pal_klp_for_each_thread(klp_stacktrace_t trace_callback, void *args);

struct liblinux_pal_rwlock_t {
	/*
	 * NOTE:
	 * the 'owner' field must be the first, due to sysmgr copy
	 * the owner of the lock by the lock address directly.
	 */
	struct {
		union {
			unsigned long id;
			unsigned long long align_id; /* ensure align in 32 and 64 data model */
		};
		union {
			const void *pc;
			unsigned long long align_pc; /* ensure align in 32 and 64 data model */
		};
	} owner;
	unsigned int lock;
	unsigned int waiters;
	struct {
		unsigned int shared : 1;
		unsigned int reserved : 31;
	} attr;
	/* For liblinux it is sufficient to ensure that the struct is >= then the HM
	   definition, so to simplify things we just unconditionally define this
	   member in liblinux. liblinux code never directly accesses the struct
	   members. */
	unsigned int _lock_id;
};

void liblinux_pal_rwlock_init(struct liblinux_pal_rwlock_t *lock);
int  liblinux_pal_rwlock_tryrdlock(struct liblinux_pal_rwlock_t *lock);
void liblinux_pal_rwlock_rdlock(struct liblinux_pal_rwlock_t *lock);
int  liblinux_pal_rwlock_trywrlock(struct liblinux_pal_rwlock_t *lock);
void liblinux_pal_rwlock_wrlock(struct liblinux_pal_rwlock_t *lock);
void liblinux_pal_rwlock_unlock(struct liblinux_pal_rwlock_t *lock);
void liblinux_pal_rwlock_destroy(struct liblinux_pal_rwlock_t *lock);

int liblinux_pal_ksys_lseek(int fd, long long offset, int whence, long long *pos);
long liblinux_pal_ksys_write(int fd, const void *buf, unsigned int nbyte);
long liblinux_pal_ksys_read(int fd, void *buf, unsigned int nbyte);
int liblinux_pal_ksys_fsync(int fd);
int liblinux_pal_ksys_close(int fd);
int liblinux_pal_ksys_rename(const char *oldpath, const char *newpath);
int liblinux_pal_ksys_mkdir(const char *pathname, unsigned int mode);
int liblinux_pal_ksys_rmdir(const char *pathname);
int liblinux_pal_ksys_openat(int dfd, const char *filename, unsigned int flag, unsigned short mode);
int liblinux_pal_ksys_access(const char *pathname, int mode);

#define RAW_RDLOCK_INITIALIZER {.owner = {{.align_id = 0ULL}, {.align_pc = 0ULL}}, .lock = 0U, \
				.waiters = 0U, .attr = {.shared = 0U, .reserved = 0U}}

/* liblinux shrinker */
struct liblinux_pal_sub_shrinker {
	unsigned long (*query)(void *priv);
	unsigned long (*shrink)(void *priv, int free_nr);
	void *priv;
};

void liblinux_pal_sub_shrinker_register(const struct liblinux_page_allocator *allocator,
					struct liblinux_pal_sub_shrinker shrinker);

void liblinux_cred_init(void);
void *liblinux_patch_map(void *addr, int fixmap);
void liblinux_patch_unmap(void *addr);
int file_is_posix_clock(void *filp);
unsigned long long liblinux_sched_clock(void);
void liblinux_timekeeping_sync(unsigned int retry_tolerance, unsigned int adj_tolerance);
#endif /* !__ASSEMBLY__ */
#endif /* CONFIG_LIBLINUX */
#endif /* __LIBLINUX_PAL_H__ */
